﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TraceMessageBase.cs" company="AzureContrib (Open source library http://azurecontrib.codeplex.com)">
//   Microsoft Public License (Ms-PL)
// </copyright>
// <summary>
//   A <see cref="Message" /> to trace to a given <see cref="Level" /> for a given <see cref="Switch" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics.CodeAnalysis;

namespace AzureContrib.WindowsAzure.Diagnostics
{
	/// <summary>
	/// A <see cref="Message"/> to trace to a given <see cref="Level"/> for a given <see cref="Switch"/>
	/// </summary>
	[Serializable]
	public abstract class TraceMessageBase
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="TraceMessageBase"/> class.
		/// </summary>
		protected TraceMessageBase()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceMessageBase"/> class. 
		/// </summary>
		/// <param name="traceMessage">A string containing the data for a <see cref="TraceMessageBase"/>.</param>
		/// <remarks>Deserialization using <see cref="FromString"/>.</remarks>
		[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "Agreed! We need this behavior here when the input is a string since diffrent sub-classes may use diffrent serialization implementations.")]
		protected TraceMessageBase(string traceMessage)
		{
			var traceMessageBase = FromString(traceMessage);
			Level = traceMessageBase.Level;
			Switch = traceMessageBase.Switch;
			Message = traceMessageBase.Message;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceMessageBase"/> class. 
		/// </summary>
		/// <param name="level">Trace level to trace at.</param>
		/// <param name="switch">Identifying switch.</param>
		/// <param name="message">The Message traced.</param>
		protected TraceMessageBase(LogLevel level, string @switch, string message)
			: this(level.ToString(), @switch, message)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceMessageBase"/> class. 
		/// </summary>
		/// <param name="level">The level to trace to.</param>
		/// <param name="switch">Identifying switch.</param>
		/// <param name="message">The Message traced.</param>
		protected TraceMessageBase(string level, string @switch, string message)
		{
			Level = level;
			Switch = @switch;
			Message = message;
		}

		/// <summary>
		/// Gets or sets the <see cref="LogLevel"/> for this trace Message.
		/// </summary>
		public string Level { get; set; }

		/// <summary>
		/// Gets or sets the identifying switch we trace from.
		/// </summary>
		public string Switch { get; set; }

		/// <summary>
		/// Gets or sets the Message traced.
		/// </summary>
		public string Message { get; set; }

		/// <summary>
		/// Turn a <see cref="string"/> into a <see cref="TraceMessage"/>.
		/// </summary>
		/// <param name="traceMessage">The <see cref="TraceMessage"/> as a <see cref="string"/>.</param>
		/// <returns>A <see cref="TraceMessage"/> created from the incomming <see cref="string"/>.</returns>
		/// <exception cref="ArgumentException">If the <paramref name="traceMessage"/> is not a valid serialized <see cref="TraceMessage"/>.</exception>
		/// <exception cref="ArgumentOutOfRangeException">If the <paramref name="traceMessage"/> is empty.</exception>
		/// <exception cref="InvalidOperationException">There is a problem deserializing the <paramref name="traceMessage"/>.</exception>
		[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "AzureContrib.WindowsAzure.Core.Assumes.NotNull handles null checking.")]
		public static implicit operator string(TraceMessageBase traceMessage)
		{
			Assumes.NotNull(traceMessage, "traceMessage");
			return traceMessage.ToString();
		}

		/// <summary>
		/// Calls serialization into known string format using <see cref="ToString(TraceMessageBase)"/>
		/// </summary>
		/// <returns>The <see cref="TraceMessageBase"/> as a <see cref="string"/>.</returns>
		public override string ToString()
		{
			return ToString(this);
		}

		/// <summary>
		/// Turn a <see cref="string"/> into a <see cref="TraceMessageBase"/> instance.
		/// </summary>
		/// <param name="traceMessage">The <see cref="TraceMessageBase"/> as a <see cref="string"/></param>
		/// <returns>A <see cref="TraceMessageBase"/> created from the <see cref="string"/>.</returns>
		protected abstract TraceMessageBase FromString(string traceMessage);

		/// <summary>
		/// Turn a <see cref="TraceMessageBase"/> into a <see cref="string"/>.
		/// </summary>
		/// <param name="traceMessageBase">The <see cref="TraceMessageBase"/>.</param>
		/// <returns>A <see cref="string"/> created from the <see cref="TraceMessageBase"/>.</returns>
		protected abstract string ToString(TraceMessageBase traceMessageBase);
	}
}